﻿namespace net.zxteam.ZXLexer.Runtime.Internal
{
	using System;
	using System.Collections.Generic;
	using System.IO;
	using System.Linq;
	using System.Text;

	internal class StateTextReader : TextReader
	{
		private readonly TextReader _wrappedTextReader;
		private readonly Stack<LexerStateScope> _scopeStack = new Stack<LexerStateScope>();
		private readonly StringBuilder _inputBuffer = new StringBuilder();

		private int _position;

		public StateTextReader(TextReader wrappedTextReader)
		{
			if (wrappedTextReader == null) throw new ArgumentNullException();

			this._wrappedTextReader = wrappedTextReader;
		}

		public int Position { get { return _position; } }

		public LexerStateScope CreateStateScope()
		{
			var stateScope = new LexerStateScope(this.Position, this.StateScopeExit);
			this._scopeStack.Push(stateScope);
			return stateScope;
		}

		public override int Peek()
		{
			if (_position < _inputBuffer.Length)
				return _inputBuffer[_position];

			int ch = _wrappedTextReader.Read();
			if (ch >= 0)
				_inputBuffer.Append((char)ch);

			return ch;
		}

		public override int Read()
		{
			if (_position < _inputBuffer.Length)
				return _inputBuffer[_position++];

			int ch = _wrappedTextReader.Read();
			if (ch >= 0)
			{
				_inputBuffer.Append((char)ch);
				++_position;
			}

			return ch;
		}

		public LexerStateScope TopStateScope
		{
			get
			{
				if (_scopeStack.Count == 0)
					return null;

				return _scopeStack.Peek();
			}
		}

		private void StateScopeExit(LexerStateScope stateScope, bool commited)
		{
			var topState = _scopeStack.Peek();
			if (topState != stateScope) throw new InvalidOperationException();

			_scopeStack.Pop();

			if (!commited)
				this._position = stateScope.InitPosition;
		}
	}
}
